13.2 方法引用

13.2.7 通过super引用成员方法

  如果存在继承关系,当Lambda中需要出现super调用时,也可以使用方法引用进行替代。首先是函数式接口:

1
2
3
4
@FunctionalInterface
public interface Greetable {
void greet();
}

  然后是父类Human的内容:

1
2
3
4
5
public class Human {
public void sayHello() {
System.out.println("Hello!");
}
}

  最后是子类Man的内容,其中使用了Lambda的写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Man extends Human {
@Override
public void sayHello() {
System.out.println("大家好,我是Man!");
}
//定义方法method,参数传递Greetable接口
public void method(Greetable g){
g.greet();
}
public void show(){
//调用method方法,使用Lambda表达式
method(()‐>{
//创建Human对象,调用sayHello方法
new Human().sayHello();
});
//简化Lambda
method(()‐>new Human().sayHello());
//使用super关键字代替父类对象
method(()‐>super.sayHello());
}
}

  但是如果使用方法引用来调用父类中的sayHello方法会更好,例如另一个子类Woman**:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Man extends Human {
@Override
public void sayHello() {
System.out.println("大家好,我是Man!");
}
//定义方法method,参数传递Greetable接口
public void method(Greetable g){
g.greet();
}
public void show(){
method(super::sayHello);
}
}

  在这个例子中,下面两种写法是等效的:

  • Lambda表达式:() -> super.sayHello()
  • 方法引用: super::sayHello

13.2.8 通过this引用成员方法

  this代表当前对象,如果需要引用的方法就是当前类中的成员方法,那么可以使用“this::成员方法”的格式来使用方法引用。首先是简单的函数式接口:

1
2
3
4
@FunctionalInterface
public interface Richable {
void buy();
}

下面是一个丈夫Husband类:

1
2
3
4
5
6
7
8
public class Husband {
private void marry(Richable lambda) {
lambda.buy();
}
public void beHappy() {
marry(() ‐> System.out.println("买套房子"));
}
}

  开心方法beHappy调用了结婚方法marry,后者的参数为函数式接口Richable,所以需要一个Lambda表达式。但是如果这个Lambda表达式的内容已经在本类当中存在了,则可以对Husband丈夫类进行修改:

1
2
3
4
5
6
7
8
9
10
11
public class Husband {
private void buyHouse() {
System.out.println("买套房子");
}
private void marry(Richable lambda) {
lambda.buy();
}
public void beHappy() {
marry(() ‐> this.buyHouse());
}
}

  如果希望取消掉Lambda表达式,用方法引用进行替换,则更好的写法为:

1
2
3
4
5
6
7
8
9
10
11
public class Husband {
private void buyHouse() {
System.out.println("买套房子");
}
private void marry(Richable lambda) {
lambda.buy();
}
public void beHappy() {
marry(this::buyHouse);
}
}

在这个例子中,下面两种写法是等效的:

  • Lambda表达式: () -> this.buyHouse()
  • 方法引用:this::buyHouse

13.2.9 类的构造器引用

  由于构造器的名称与类名完全一样,并不固定。所以构造器引用使用 类名称::new 的格式表示。首先是一个简单的Person类:

1
2
3
4
5
6
7
8
9
10
11
12
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

  然后是用来创建Person 对象的函数式接口:

1
2
3
public interface PersonBuilder {
Person buildPerson(String name);
}

  要使用这个函数式接口,可以通过Lambda表达式:

1
2
3
4
5
6
7
8
public class Demo09Lambda {
public static void printName(String name, PersonBuilder builder) {
System.out.println(builder.buildPerson(name).getName());
}
public static void main(String[] args) {
printName("赵丽颖", name ‐> new Person(name));
}
}

  但是通过构造器引用,有更好的写法:

1
2
3
4
5
6
7
8
public class Demo10ConstructorRef {
public static void printName(String name, PersonBuilder builder) {
System.out.println(builder.buildPerson(name).getName());
}
public static void main(String[] args) {
printName("赵丽颖", Person::new);
}
}

  在这个例子中,下面两种写法是等效的:

  • Lambda表达式:name -> new Person(name)
  • 方法引用: Person::new

13.2.10 数组的构造器引用

  数组也是Object的子类对象,所以同样具有构造器,只是语法稍有不同。如果对应到Lambda的使用场景中时,需要一个函数式接口:

1
2
3
4
@FunctionalInterface
public interface ArrayBuilder {
int[] buildArray(int length);
}

  在应用该接口的时候,可以通过Lambda表达式:

1
2
3
4
5
6
7
8
public class Demo11ArrayInitRef {
private static int[] initArray(int length, ArrayBuilder builder) {
return builder.buildArray(length);
}
public static void main(String[] args) {
int[] array = initArray(10, length ‐> new int[length]);
}
}

  但是更好的写法是使用数组的构造器引用:

1
2
3
4
5
6
7
8
public class Demo12ArrayInitRef {
private static int[] initArray(int length, ArrayBuilder builder) {
return builder.buildArray(length);
}
public static void main(String[] args) {
int[] array = initArray(10, int[]::new);
}
}

  在这个例子中,下面两种写法是等效的:

  • Lambda表达式:length -> new int[length]
  • 方法引用:int[]::new